home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 25 / Cream of the Crop 25.iso / faq / wdj0597.zip / ROBBINS.ZIP / DEFMAKER.CPP next >
C/C++ Source or Header  |  1997-03-10  |  8KB  |  231 lines

  1. #define WIN32_LEAN_AND_MEAN
  2. #include <windows.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include "PEImage.h"
  6.  
  7. // The usage message.
  8. void ShowUsage ( void ) ;
  9.  
  10. static char szSTDCallProblem[] =
  11. "A non-decorated function call is exported.  Unfortunately, there "
  12. "is no way to turn a _stdcall function export into something in "
  13. "the .DEF file without knowing the complete byte parameter count.  "
  14. "If you know for sure that the function in the title bar is _cdecl,"
  15. " then you can press OK now. Otherwise, press CANCEL to save "
  16. "yourself some grief." ;
  17.  
  18. int main ( int argc , char * argv[] )
  19. {
  20.     printf ( "DEFMaker - The exports to .DEF file maker - "
  21.              "John Robbins 1997\n"                       ) ;
  22.  
  23.     if ( 1 == argc )
  24.     {
  25.         ShowUsage ( ) ;
  26.         return ( 1 ) ;
  27.     }
  28.  
  29.     // See if the input file exists.
  30.     WIN32_FIND_DATA stWFD ;
  31.     HANDLE hFind = FindFirstFile ( argv[ 1 ] , &stWFD ) ;
  32.     if ( INVALID_HANDLE_VALUE == hFind )
  33.     {
  34.         printf ( "%s does not exist\n" , argv[ 1 ] ) ;
  35.         return ( 1 ) ;
  36.     }
  37.     FindClose ( hFind ) ;
  38.  
  39.     char szFile[ MAX_PATH ] ;
  40.     _splitpath ( argv[ 1 ] , NULL , NULL , szFile , NULL ) ;
  41.  
  42.     // Now figure out the name of the output file.
  43.     char szOutput[ MAX_PATH ] ;
  44.     if ( 2 == argc )
  45.     {
  46.         strcpy ( szOutput , szFile ) ;
  47.         strcat ( szOutput , ".def" ) ;
  48.     }
  49.     else
  50.     {
  51.         strcpy ( szOutput , argv [ 2 ] ) ;
  52.     }
  53.  
  54.     // Try and open the output file.
  55.     FILE * fileOut = fopen ( szOutput , "wt" ) ;
  56.     if ( NULL == fileOut )
  57.     {
  58.         printf ( "Unable to open %s\n" , szOutput ) ;
  59.         return ( 1 ) ;
  60.     }
  61.  
  62.     // Stick all of the header information into the .DEF file.
  63.     fprintf ( fileOut , "; DEFMaker Generated .DEF file\n\n" ) ;
  64.     fprintf ( fileOut , "LIBRARY %s\n\n" , szFile ) ;
  65.     fprintf ( fileOut , "EXPORTS\n" ) ;
  66.  
  67.  
  68.     // We are ready to roll.  Everything is put in a try catch block
  69.     //  to make it easier to control resource cleanup.
  70.     // The error buffer
  71.     char szErrBuff[ 150 ] ;
  72.     try
  73.     {
  74.  
  75.         // The PE File object.
  76.         CPEImage cPE ;
  77.  
  78.         // Try and open the file.
  79.         PEI_ERROR pErr = cPE.LoadImage ( argv[ 1 ] ) ;
  80.         if ( PEI_NOERROR != pErr )
  81.         {
  82.             sprintf ( szErrBuff , "Unable to open %s\n" , argv[1] );
  83.             throw szErrBuff ;
  84.         }
  85.  
  86.         // Now that we have it open, get the exports data.
  87.         DWORD dwExportsRVA =
  88.                cPE.
  89.                   GetDataDirectoryRVA(IMAGE_DIRECTORY_ENTRY_EXPORT);
  90.         if ( NULL == dwExportsRVA )
  91.         {
  92.             sprintf ( szErrBuff , "%s has no exports!\n" , argv[1]);
  93.             throw szErrBuff ;
  94.         }
  95.  
  96.         // Get the pointer to the exports directory.
  97.         PIMAGE_EXPORT_DIRECTORY pExpDir = (PIMAGE_EXPORT_DIRECTORY)
  98.                                  cPE.ImageRvaToFileVa(dwExportsRVA);
  99.  
  100.         // Before we do anything else we check that the number of
  101.         //  functions matches the number of exports.  If they do
  102.         //  not, then somewhere in the file are NONAME exports.
  103.         if ( pExpDir->NumberOfFunctions != pExpDir->NumberOfNames )
  104.         {
  105.                 sprintf ( szErrBuff                                ,
  106.                           "The number of exports and number of "
  107.                           "names do not match.  There is a NONAME "
  108.                           "export in %s.\n"                        ,
  109.                           argv[ 1 ]                               );
  110.                 throw szErrBuff ;
  111.         }
  112.  
  113.         // Get the pointer to the function address array.
  114.         PDWORD pdwAddr = (PDWORD)
  115.                cPE.ImageRvaToFileVa((DWORD)pExpDir->
  116.                                                 AddressOfFunctions);
  117.  
  118.         // Get the pointer to the function address array.
  119.         PWORD pwOrdinal = (PWORD)
  120.             cPE.ImageRvaToFileVa((DWORD)pExpDir->
  121.                                              AddressOfNameOrdinals);
  122.  
  123.         // Get the address to the names array.
  124.         LPSTR *pszName = (PSTR *)
  125.                    cPE.ImageRvaToFileVa((DWORD)pExpDir->
  126.                                                     AddressOfNames);
  127.  
  128.         // The current name we are looking at.
  129.         LPSTR szExpName ;
  130.         // The buffer where undecorated names are stored.
  131.         char szUnDec [ 1024 ] ;
  132.         // If there is an undecorated function, and the user has
  133.         //  already indicated that they want to continue, don't keep
  134.         //  prompting them.
  135.         BOOL bContinueAnyway = FALSE ;
  136.         for ( DWORD i = 0 ; i < pExpDir->NumberOfFunctions ; i++ )
  137.         {
  138.             // If this is just a gap in the exports, skip over it.
  139.             if ( 0 == pdwAddr [ i ] )
  140.             {
  141.                 continue ;
  142.             }
  143.             szExpName = NULL ;
  144.  
  145.             // Get the name address
  146.             szExpName =
  147.                      (LPSTR)cPE.ImageRvaToFileVa((DWORD)pszName[i]);
  148.  
  149.             // If the first character is NOT a question mark,
  150.             //  we have a problem.  However, if the user has
  151.             //  already indicated that they want
  152.             if ( ( '?' != *szExpName ) &&
  153.                  ( FALSE == bContinueAnyway ) )
  154.             {
  155.                 // Could it be a __stdcall export or __fastcall done
  156.                 //  through __declspec(dllexport) or put in the .DEF
  157.                 //  file that way?
  158.                 if ( ( ( '_' != *szExpName ) ||
  159.                        ( '@' != *szExpName )                   )&&
  160.                      ( NULL == strrchr ( szExpName + 1 , '@' ) )   )
  161.                 {
  162.                     // OK, pop up the message box.
  163.                     if ( IDOK ==
  164.                             MessageBox ( GetActiveWindow ( )  ,
  165.                                          szSTDCallProblem     ,
  166.                                          szExpName            ,
  167.                                          MB_OKCANCEL |
  168.                                                 MB_ICONWARNING  ) )
  169.                     {
  170.                         bContinueAnyway = TRUE ;
  171.                     }
  172.                     else
  173.                     {
  174.                         throw "User ended operation." ;
  175.                     }
  176.                 }
  177.             }
  178.  
  179.             // If this is a name that can be undecorated, we will
  180.             //  show it in a comment in the output file.
  181.             if ( 0 !=
  182.                   UnDecorateSymbolName( szExpName               ,
  183.                                         szUnDec                 ,
  184.                                         sizeof ( szUnDec )      ,
  185.                                         UNDNAME_NO_MS_KEYWORDS   ) )
  186.             {
  187.                 fprintf ( fileOut , "; %s\n" , szUnDec ) ;
  188.             }
  189.             // Notice that we are adding the starting base to the
  190.             //  output ordinal.  We don't want to get this out of
  191.             //  whack.
  192.             fprintf ( fileOut                           ,
  193.                       "    %s @%d NONAME\n\n"           ,
  194.                       szExpName                         ,
  195.                       pwOrdinal[ i ] + pExpDir->Base     ) ;
  196.             // Do a little visual clue.
  197.             putchar ( '.' ) ;
  198.  
  199.         }
  200.     }
  201.     catch ( char * szError )
  202.     {
  203.         printf ( "\n%s\n" , szError ) ;
  204.         // Close the output file.
  205.         fclose ( fileOut ) ;
  206.         // Don't leave any half backed files around.
  207.         DeleteFile ( szOutput ) ;
  208.         return ( 1 ) ;
  209.     }
  210.     // Close the output file.
  211.     fclose ( fileOut ) ;
  212.     return ( 0 ) ;
  213. }
  214.  
  215.  
  216. // Shows the usage message.
  217. void ShowUsage ( void )
  218. {
  219.     printf (
  220. "Usage : DEFMaker <input dll> [output file]\n\n"
  221. " <input dll>   - The DLL with exports.  Specify the complete \n"
  222. "                 filename to the DLL.\n"
  223. " [output file] - The optional output file.  If not specified,\n"
  224. "                 the output is the input filename with .DEF for\n"
  225. "                 the extension. The output file is ALWAYS placed\n"
  226. "                 in the current directory if not explicitly\n"
  227. "                 set.\n\n"
  228.             ) ;
  229. }
  230.  
  231.